home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / alpha.arc / LAPB.C < prev    next >
C/C++ Source or Header  |  1988-07-26  |  15KB  |  621 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9.  
  10. /* Process incoming frames */
  11. int
  12. lapb_input(axp,cmdrsp,bp)
  13. struct ax25_cb *axp;        /* Link control structure */
  14. char cmdrsp;            /* Command/response flag */
  15. struct mbuf *bp;        /* Rest of frame, starting with ctl */
  16. {
  17.     int16 ftype();
  18.     void lapbstate();
  19.     char control;
  20.     char class;        /* General class (I/S/U) of frame */
  21.     int16 type;        /* Specific type (I/RR/RNR/etc) of frame */
  22.     char pf;        /* extracted poll/final bit */
  23.     char poll = 0;
  24.     char final = 0;
  25.     int nr;            /* ACK number of incoming frame */
  26.     int ns;            /* Seq number of incoming frame */
  27.     char tmp;
  28.  
  29.     if(bp == NULLBUF || axp == NULLAX25){
  30.         free_p(bp);
  31.         return -1;
  32.     }
  33.  
  34.     /* Extract the various parts of the control field for easy use */
  35.     control = pullchar(&bp);
  36.     type = ftype(control);
  37.     class = type & 0x3;
  38.     pf = control & PF;
  39.     /* Check for polls and finals */
  40.     if(pf){
  41.         switch(cmdrsp){
  42.         case COMMAND:
  43.             poll = YES;
  44.             break;
  45.         case RESPONSE:
  46.             final = YES;
  47.             break;
  48.         }
  49.     }
  50.     /* Extract sequence numbers, if present */
  51.     switch(class){
  52.     case I:
  53.     case I+2:
  54.         ns = (control >> 1) & MMASK;
  55.     case S:    /* Note fall-thru */
  56.         nr = (control >> 5) & MMASK;
  57.         break;
  58.     }
  59.     /* This section follows the SDL diagrams by K3NA fairly closely */
  60.     switch(axp->state){
  61.     case DISCONNECTED:
  62.         switch(type){
  63.         case SABM:    /* Initialize or reset link */
  64.             sendctl(axp,RESPONSE,UA|pf);    /* Always accept */
  65.             clr_ex(axp);
  66.             axp->unack = axp->vr = axp->vs = 0;
  67.             lapbstate(axp,CONNECTED);/* Resets state counters */
  68.             start_timer(&axp->t3);
  69.             break;
  70.         case DM:    /* Ignore to avoid infinite loops */
  71.             break;
  72.         default:    /* All others get DM */
  73.             sendctl(axp,RESPONSE,DM|pf);
  74.             break;
  75.         }
  76.         break;
  77.     case SETUP:
  78.         switch(type){
  79.         case SABM:    /* Simultaneous open */
  80.             sendctl(axp,RESPONSE,UA|pf);
  81.             break;
  82.         case DISC:
  83.             sendctl(axp,RESPONSE,DM|pf);
  84.             break;
  85.         case UA:    /* Connection accepted */
  86.             /* Note: xmit queue not cleared */
  87.             stop_timer(&axp->t1);
  88.             start_timer(&axp->t3);
  89.             axp->unack = axp->vr = axp->vs = 0;
  90.             lapbstate(axp,CONNECTED);
  91.             break;            
  92.         case DM:    /* Connection refused */
  93.             free_q(&axp->txq);
  94.             stop_timer(&axp->t1);
  95.             lapbstate(axp,DISCONNECTED);
  96.             break;
  97.         default:    /* All other frames ignored */
  98.             break;
  99.         }
  100.         break;
  101.     case DISCPENDING:
  102.         switch(type){
  103.         case SABM:
  104.             sendctl(axp,RESPONSE,DM|pf);
  105.             break;
  106.         case DISC:
  107.             sendctl(axp,RESPONSE,UA|pf);
  108.             break;
  109.         case UA:
  110.         case DM:
  111.             stop_timer(&axp->t1);
  112.             lapbstate(axp,DISCONNECTED);
  113.             break;
  114.         default:    /* Respond with DM only to command polls */
  115.             if(poll)
  116.                 sendctl(axp,RESPONSE,DM|pf);
  117.             break;
  118.         }
  119.         break;
  120.     case CONNECTED:
  121.         switch(type){
  122.         case SABM:
  123.             sendctl(axp,RESPONSE,UA|pf);
  124.             clr_ex(axp);
  125.             free_q(&axp->txq);
  126.             stop_timer(&axp->t1);
  127.             start_timer(&axp->t3);
  128.             axp->unack = axp->vr = axp->vs = 0;
  129.             lapbstate(axp,CONNECTED); /* Purge queues */
  130.             break;
  131.         case DISC:
  132.             free_q(&axp->txq);
  133.             sendctl(axp,RESPONSE,UA|pf);
  134.             stop_timer(&axp->t1);
  135.             stop_timer(&axp->t3);
  136.             lapbstate(axp,DISCONNECTED);
  137.             break;
  138.         case UA:
  139.         case DM:
  140.             frmr(axp,control,W);
  141.             est_link(axp);
  142.             lapbstate(axp,SETUP);    /* Re-establish */    
  143.             break;            
  144.         case FRMR:
  145.             est_link(axp);
  146.             lapbstate(axp,SETUP);    /* Re-establish link */
  147.             break;
  148.         case RR:
  149.         case RNR:
  150.             axp->remotebusy = (control == RNR) ? YES : NO;
  151.             if(poll)
  152.                 enq_resp(axp);
  153.             ackours(axp,nr);
  154.             break;
  155.         case REJ:
  156.             axp->remotebusy = NO;
  157.             if(poll)
  158.                 enq_resp(axp);
  159.             ackours(axp,nr);
  160.             stop_timer(&axp->t1);
  161.             start_timer(&axp->t3);
  162.             /* This may or may not actually invoke transmission,
  163.              * depending on whether this REJ was caused by
  164.              * our losing his prior ACK.
  165.              */
  166.             inv_rex(axp);
  167.             break;    
  168.         case I:
  169.             ackours(axp,nr); /** == -1) */
  170.             if(len_mbuf(axp->rxq) >= axp->window){
  171.                 /* Too bad he didn't listen to us; he'll
  172.                  * have to resend the frame later. This
  173.                  * drastic action is necessary to avoid
  174.                  * deadlock.
  175.                  */
  176.                 if(poll)
  177.                     sendctl(axp,RESPONSE,RNR|pf);
  178.                 free_p(bp);
  179.                 bp = NULLBUF;
  180.                 break;
  181.             }
  182.             /* Reject or ignore I-frames with receive sequence number errors */
  183.             if(ns != axp->vr){
  184.                 if(axp->proto == V1 || !axp->rejsent){
  185.                     axp->rejsent = YES;
  186.                     sendctl(axp,RESPONSE,REJ | pf);
  187.                 }
  188.                 axp->response = 0;
  189.                 stop_timer(&axp->t2);
  190.                 break;
  191.             }
  192.             axp->rejsent = NO;
  193.             axp->vr = (axp->vr+1) & MMASK;
  194.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  195.             if(poll){
  196.                 sendctl(axp,RESPONSE,tmp|PF);
  197.             } else {
  198.                 axp->response = tmp;
  199.                 start_timer(&axp->t2);
  200.             }
  201.             procdata(axp,bp);
  202.             bp = NULLBUF;
  203.             break;
  204.         default:    /* All others ignored */
  205.             break;
  206.         }
  207.         break;
  208.     case RECOVERY:
  209.         switch(type){
  210.         case SABM:
  211.             sendctl(axp,RESPONSE,UA|pf);
  212.             clr_ex(axp);
  213.             stop_timer(&axp->t1);
  214.             start_timer(&axp->t3);
  215.             axp->unack = axp->vr = axp->vs = 0;
  216.             lapbstate(axp,CONNECTED); /* Purge queues */
  217.             break;
  218.         case DISC:
  219.             free_q(&axp->txq);
  220.             sendctl(axp,RESPONSE,UA|pf);
  221.             stop_timer(&axp->t1);
  222.             stop_timer(&axp->t3);
  223.             axp->response = UA;
  224.             lapbstate(axp,DISCONNECTED);
  225.             break;
  226.         case UA:
  227.         case DM:
  228.             frmr(axp,control,W);
  229.             est_link(axp);
  230.             lapbstate(axp,SETUP);    /* Re-establish */    
  231.             break;
  232.         case FRMR:
  233.             est_link(axp);
  234.             lapbstate(axp,SETUP);    /* Re-establish link */
  235.             break;
  236.         case RR:
  237.         case RNR:
  238.             axp->remotebusy = (control == RNR) ? YES : NO;
  239.             if(axp->proto == V1 || final){
  240.                 stop_timer(&axp->t1);
  241.                 ackours(axp,nr);
  242.                 if(axp->unack != 0){
  243.                     inv_rex(axp);
  244.                 } else {
  245.                     start_timer(&axp->t3);
  246.                     lapbstate(axp,CONNECTED);
  247.                 }
  248.             } else {
  249.                 if(poll)
  250.                     enq_resp(axp);
  251.                 ackours(axp,nr);
  252.                 /* Keep timer running even if all frames
  253.                  * were acked, since we must see a Final
  254.                  */
  255.                 if(!run_timer(&axp->t1))
  256.                     start_timer(&axp->t1);
  257.             }
  258.             break;
  259.         case REJ:
  260.             axp->remotebusy = NO;
  261.             /* Don't insist on a Final response from the old proto */
  262.             if(axp->proto == V1 || final){
  263.                 stop_timer(&axp->t1);
  264.                 ackours(axp,nr);
  265.                 if(axp->unack != 0){
  266.                     inv_rex(axp);
  267.                 } else {
  268.                     start_timer(&axp->t3);
  269.                     lapbstate(axp,CONNECTED);
  270.                 }
  271.             } else {
  272.                 if(poll)
  273.                     enq_resp(axp);
  274.                 ackours(axp,nr);
  275.                 if(axp->unack != 0){
  276.                     /* This is certain to trigger output */
  277.                     inv_rex(axp);
  278.                 }
  279.                 /* A REJ that acks everything but doesn't
  280.                  * have the F bit set can cause a deadlock.
  281.                  * So make sure the timer is running.
  282.                  */
  283.                 if(!run_timer(&axp->t1))
  284.                     start_timer(&axp->t1);
  285.             }
  286.             break;
  287.         case I:
  288.             ackours(axp,nr); /** == -1) */
  289.             /* Make sure timer is running, since an I frame
  290.              * cannot satisfy a poll
  291.              */
  292.             if(!run_timer(&axp->t1))
  293.                 start_timer(&axp->t1);
  294.             if(len_mbuf(axp->rxq) >= axp->window){
  295.                 /* Too bad he didn't listen to us; he'll
  296.                  * have to resend the frame later. This
  297.                  * drastic action is necessary to avoid
  298.                  * memory deadlock.
  299.                  */
  300.                 sendctl(axp,RESPONSE,RNR | pf);
  301.                 free_p(bp);
  302.                 bp = NULLBUF;
  303.                 break;
  304.             }
  305.             /* Reject or ignore I-frames with receive sequence number errors */
  306.             if(ns != axp->vr){
  307.                 if(axp->proto == V1 || !axp->rejsent){
  308.                     axp->rejsent = YES;
  309.                     sendctl(axp,RESPONSE,REJ | pf);
  310.                 }
  311.                 axp->response = 0;
  312.                 stop_timer(&axp->t2);
  313.                 break;
  314.             }
  315.             axp->rejsent = NO;
  316.             axp->vr = (axp->vr+1) & MMASK;
  317.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  318.             if(poll){
  319.                 sendctl(axp,RESPONSE,tmp|PF);
  320.             } else {
  321.                 axp->response = tmp;
  322.                 start_timer(&axp->t2);
  323.             }
  324.             procdata(axp,bp);
  325.             bp = NULLBUF;
  326.             break;
  327.         default:
  328.             break;        /* Ignored */
  329.         }
  330.         break;
  331.     case FRAMEREJECT:
  332.         switch(type){
  333.         case SABM:
  334.             sendctl(axp,RESPONSE,UA|pf);
  335.             clr_ex(axp);
  336.             axp->unack = axp->vr = axp->vs = 0;
  337.             stop_timer(&axp->t1);
  338.             start_timer(&axp->t3);
  339.             lapbstate(axp,CONNECTED);
  340.             break;
  341.         case DISC:
  342.             free_q(&axp->txq);
  343.             sendctl(axp,RESPONSE,UA|pf);
  344.             stop_timer(&axp->t1);
  345.             lapbstate(axp,DISCONNECTED);
  346.             break;
  347.         case DM:
  348.             stop_timer(&axp->t1);
  349.             lapbstate(axp,DISCONNECTED);
  350.             break;
  351.         default:
  352.             frmr(axp,0,0);
  353.             break;
  354.         }
  355.         break;
  356.     }
  357.     free_p(bp);    /* In case anything's left */
  358.  
  359.     /* See if we can send some data, perhaps piggybacking an ack.
  360.      * If successful, lapb_output will clear axp->response.
  361.      */
  362.     lapb_output(axp);
  363.  
  364.     /* Empty the trash */
  365.     if(axp->state == DISCONNECTED)
  366.         del_ax25(axp);
  367.     return 0;
  368. }
  369. /* Handle incoming acknowledgements for frames we've sent.
  370.  * Free frames being acknowledged.
  371.  * Return -1 to cause a frame reject if number is bad, 0 otherwise
  372.  */
  373. static int
  374. ackours(axp,n)
  375. struct ax25_cb *axp;
  376. char n;
  377. {    
  378.     struct mbuf *bp;
  379.     int acked = 0;    /* Count of frames acked by this ACK */
  380.     int oldest;    /* Seq number of oldest unacked I-frame */
  381.  
  382.     /* Free up acknowledged frames by purging frames from the I-frame
  383.      * transmit queue. Start at the remote end's last reported V(r)
  384.      * and keep going until we reach the new sequence number.
  385.      * If we try to free a null pointer,
  386.      * then we have a frame reject condition.
  387.      */
  388.     oldest = (axp->vs - axp->unack) & MMASK;
  389.     while(axp->unack != 0 && oldest != n){
  390.         if((bp = dequeue(&axp->txq)) == NULLBUF){
  391.             /* Acking unsent frame */
  392.             return -1;
  393.         }
  394.         free_p(bp);
  395.         axp->unack--;
  396.         acked++;
  397.         axp->retries = 0;
  398.         oldest = (oldest + 1) & MMASK;
  399.     }
  400.     if(axp->unack == 0){
  401.         /* All frames acked, stop timeout */
  402.         stop_timer(&axp->t1);
  403.         start_timer(&axp->t3);
  404.     } else if(acked != 0) { 
  405.         /* Partial ACK; restart timer */
  406.         start_timer(&axp->t1);
  407.     }
  408.     /* If user has set a transmit upcall, indicate how many frames
  409.      * may be queued
  410.      */
  411.     if(acked != 0 && axp->t_upcall != NULLVFP)
  412.         (*axp->t_upcall)(axp,axp->paclen * (axp->maxframe - axp->unack));
  413.  
  414.     return 0;
  415. }
  416.  
  417. /* Establish data link */
  418. est_link(axp)
  419. struct ax25_cb *axp;
  420. {
  421.     clr_ex(axp);
  422.     axp->retries = 0;
  423.     sendctl(axp,COMMAND,SABM|PF);
  424.     stop_timer(&axp->t3);
  425.     start_timer(&axp->t1);
  426. }
  427. /* Clear exception conditions */
  428. clr_ex(axp)
  429. struct ax25_cb *axp;
  430. {
  431.     axp->remotebusy = NO;
  432.     axp->rejsent = NO;
  433.     axp->response = 0;
  434.     stop_timer(&axp->t3);
  435. }
  436. /* Enquiry response */
  437. enq_resp(axp)
  438. struct ax25_cb *axp;
  439. {
  440.     char ctl;
  441.  
  442.     ctl = len_mbuf(axp->rxq) >= axp->window ? RNR|PF : RR|PF;    
  443.     sendctl(axp,RESPONSE,ctl);
  444.     axp->response = 0;
  445.     stop_timer(&axp->t3);
  446. }
  447. /* Invoke retransmission */
  448. inv_rex(axp)
  449. struct ax25_cb *axp;
  450. {
  451.     axp->vs -= axp->unack;
  452.     axp->vs &= MMASK;
  453.     axp->unack = 0;
  454. }
  455. /* Generate Frame Reject (FRMR) response
  456.  * If reason != 0, this is the initial error frame
  457.  * If reason == 0, resend the last error frame
  458.  */
  459. int
  460. frmr(axp,control,reason)
  461. register struct ax25_cb *axp;
  462. char control;
  463. char reason;
  464. {
  465.     struct mbuf *frmrinfo;
  466.     register char *cp;
  467.     void lapbstate();
  468.  
  469.     if(reason != 0){
  470.         cp = axp->frmrinfo;
  471.         *cp++ = control;
  472.         *cp++ =  axp->vr << 5 || axp->vs << 1;
  473.         *cp = reason;
  474.     }
  475.     if((frmrinfo = alloc_mbuf(3)) == NULLBUF)
  476.         return -1;    /* No memory */
  477.     frmrinfo->cnt = 3;
  478.     memcpy(frmrinfo->data,axp->frmrinfo,3);
  479.     return sendframe(axp,RESPONSE,FRMR|(control&PF),frmrinfo);
  480. }
  481.  
  482. /* Send S or U frame to currently connected station */
  483. int
  484. sendctl(axp,cmdrsp,cmd)
  485. struct ax25_cb *axp;
  486. char cmdrsp,cmd;
  487. {
  488.     int16 ftype();
  489.  
  490.     if((ftype(cmd) & 0x3) == S)    /* Insert V(R) if S frame */
  491.         cmd |= (axp->vr << 5);
  492.     return sendframe(axp,cmdrsp,cmd,NULLBUF);
  493. }
  494. /* Start data transmission on link, if possible
  495.  * Return number of frames sent
  496.  */
  497. int
  498. lapb_output(axp)
  499. register struct ax25_cb *axp;
  500. {
  501.     register struct mbuf *bp;
  502.     struct mbuf *tbp;
  503.     char control;
  504.     int sent = 0;
  505.     int i;
  506.  
  507.     if(axp == NULLAX25
  508.      || (axp->state != RECOVERY && axp->state != CONNECTED)
  509.      || axp->remotebusy)
  510.         return 0;
  511.  
  512.     /* Dig into the send queue for the first unsent frame */
  513.     bp = axp->txq;
  514.     for(i = 0; i < axp->unack; i++){
  515.         if(bp == NULLBUF)
  516.             break;    /* Nothing to do */
  517.         bp = bp->anext;
  518.     }
  519.     /* Start at first unsent I-frame, stop when either the
  520.      * number of unacknowledged frames reaches the maxframe limit,
  521.      * or when there are no more frames to send
  522.      */
  523.     while(bp != NULLBUF && axp->unack < axp->maxframe){
  524.         control = I | (axp->vs++ << 1) | (axp->vr << 5);
  525.         axp->vs &= MMASK;
  526.         dup_p(&tbp,bp,0,len_mbuf(bp));
  527.         if(tbp == NULLBUF)
  528.             return sent;    /* Probably out of memory */
  529.         sendframe(axp,COMMAND,control,tbp);
  530.         axp->unack++;
  531.         /* We're implicitly acking any data he's sent, so stop any
  532.          * delayed ack
  533.          */
  534.         axp->response = 0;
  535.         stop_timer(&axp->t2);
  536.         if(!run_timer(&axp->t1)){
  537.             stop_timer(&axp->t3);
  538.             start_timer(&axp->t1);
  539.         }
  540.         sent++;
  541.         bp = bp->anext;
  542.     }
  543.     return sent;
  544. }
  545. /* Set new link state.
  546.  * If the new state is disconnected, also free the link control block.
  547.  */
  548. void
  549. lapbstate(axp,s)
  550. struct ax25_cb *axp;
  551. int s;
  552. {
  553.     int oldstate;
  554.  
  555.     oldstate = axp->state;
  556.     axp->state = s;
  557.     if(s == DISCONNECTED){
  558.         stop_timer(&axp->t1);
  559.         stop_timer(&axp->t2);
  560.         stop_timer(&axp->t3);
  561.         free_q(&axp->txq);
  562.     }
  563.     /* Don't bother the client unless the state is really changing */
  564.     if(oldstate != s && axp->s_upcall != NULLVFP)
  565.         (*axp->s_upcall)(axp,oldstate,s);
  566. }
  567. /* Process a valid incoming I frame */
  568. static
  569. procdata(axp,bp)
  570. struct ax25_cb *axp;
  571. struct mbuf *bp;
  572. {
  573.     char pid;
  574.     int ip_route();
  575.  
  576.     /* Extract level 3 PID */
  577.     if(pullup(&bp,&pid,1) != 1)
  578.         return;    /* No PID */
  579.  
  580.     switch(pid & (PID_FIRST|PID_LAST)){
  581.     case PID_FIRST:
  582.         /* "Shouldn't happen", but flush any accumulated frags */
  583.         free_p(axp->rxasm);
  584.         axp->rxasm = NULLBUF;
  585.     case 0:    /* Note fall-thru */
  586.         /* Beginning or middle of message, just accumulate */
  587.         append(&axp->rxasm,bp);
  588.         return;
  589.     case PID_LAST:
  590.         /* Last frame of multi-frame message; extract it */
  591.         append(&axp->rxasm,bp);
  592.         bp = axp->rxasm;
  593.         axp->rxasm = NULLBUF;
  594.         break;
  595.     case PID_FIRST|PID_LAST:
  596.         /* Do nothing with reassembly queue, allowing single-frame
  597.          * messages to be interspersed with fragments of multi-frame
  598.          * messages
  599.          */
  600.         break;
  601.     }
  602.     /* Last frame in sequence; kick entire message upstairs */
  603.     switch(pid & PID_PID){
  604.     case PID_IP:        /* DoD Internet Protocol */
  605.         ip_route(bp,0);
  606.         break;
  607.     case PID_NO_L3:        /* Enqueue for application */
  608.         append(&axp->rxq,bp);
  609.         if(axp->r_upcall != NULLVFP)
  610.             (*axp->r_upcall)(axp,len_mbuf(axp->rxq));
  611.         break;    
  612.     case PID_NETROM:
  613.         nr_route(bp);
  614.         break;
  615.     default:        /* Note: ARP is invalid here */    
  616.         free_p(bp);
  617.         break;            
  618.     }
  619. }
  620.  
  621.